package com.artisan.springuitls.demos;

import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Component;

/**
 * AopProxyUtils 和 AopUtils 工具类演示
 * 功能：AOP 代理解密器
 * 优势：获取 CGLIB 代理对象的真实类型，避免 getClass() 返回代理类
 * 
 * ⚠️ 提醒：仅用于调试/日志，业务代码不应依赖此工具
 */
@Component
public class AopProxyUtilsDemo {

    /**
     * 场景：调试 AOP 代理对象
     */
    public void analyzeProxy() {
        System.out.println("\n========== AopProxyUtils Demo ==========");
        
        // 模拟一个服务对象（实际应用中会是 Spring 代理对象）
        PaymentService service = new PaymentService();
        
        // 1. 检查是否为 AOP 代理
        boolean isProxy = AopUtils.isAopProxy(service);
        System.out.println("✓ 是否为 AOP 代理: " + isProxy);
        
        // 2. 检查是否为 CGLIB 代理
        boolean isCglibProxy = AopUtils.isCglibProxy(service);
        System.out.println("✓ 是否为 CGLIB 代理: " + isCglibProxy);
        
        // 3. 检查是否为 JDK 动态代理
        boolean isJdkProxy = AopUtils.isJdkDynamicProxy(service);
        System.out.println("✓ 是否为 JDK 动态代理: " + isJdkProxy);
        
        // 4. 获取真实类型
        Class<?> targetClass = getTargetClass(service);
        System.out.println("✓ 目标类: " + targetClass.getName());
        
        // 5. 对比：直接获取类型
        System.out.println("✓ 直接 getClass: " + service.getClass().getName());
    }

    /**
     * 演示代理类型判断
     */
    public void demonstrateProxyDetection() {
        System.out.println("\n--- 代理类型检测 ---");
        
        // 模拟不同类型的对象
        Object normalObject = new PaymentService();
        Object stringObject = "测试字符串";
        
        System.out.println("✓ PaymentService 是否为代理: " + AopUtils.isAopProxy(normalObject));
        System.out.println("✓ String 是否为代理: " + AopUtils.isAopProxy(stringObject));
        
        // 检查类是否为代理类
        System.out.println("✓ PaymentService.class 是否为代理类: false");
    }

    /**
     * 演示获取代理目标对象
     */
    public void demonstrateTargetRetrieval() {
        System.out.println("\n--- 获取代理目标 ---");
        
        PaymentService service = new PaymentService();
        
        // 在实际 Spring AOP 场景中，可以这样获取目标对象：
        // if (service instanceof Advised) {
        //     try {
        //         Object target = ((Advised) service).getTargetSource().getTarget();
        //         System.out.println("目标对象: " + target);
        //     } catch (Exception e) {
        //         e.printStackTrace();
        //     }
        // }
        
        System.out.println("✓ 在实际应用中，通过 Advised 接口可获取代理目标对象");
        System.out.println("✓ 示例：((Advised) proxy).getTargetSource().getTarget()");
    }

    /**
     * 演示实用工具方法
     */
    public void demonstrateUtilityMethods() {
        System.out.println("\n--- AOP 工具方法 ---");
        
        PaymentService service = new PaymentService();
        
        // 1. 判断是否实现了指定接口
        boolean implementsInterface = implementsInterface(service, PaymentInterface.class);
        System.out.println("✓ 是否实现 PaymentInterface: " + implementsInterface);
        
        // 2. 获取目标类（处理代理）
        Class<?> targetClass = getTargetClass(service);
        System.out.println("✓ 目标类名: " + targetClass.getSimpleName());
        
        // 3. 选择合适的调用方法
        System.out.println("✓ 建议：使用 AopUtils.invokeJoinpointUsingReflection() 调用目标方法");
        
        System.out.println("==========================================\n");
    }

    /**
     * 辅助方法：获取目标类
     */
    private Class<?> getTargetClass(Object candidate) {
        // 在实际应用中使用：AopProxyUtils.ultimateTargetClass(candidate)
        // 这里简化处理
        return candidate.getClass();
    }

    /**
     * 辅助方法：检查是否实现接口
     */
    private boolean implementsInterface(Object object, Class<?> interfaceClass) {
        return interfaceClass.isAssignableFrom(object.getClass());
    }

    /**
     * 模拟支付接口
     */
    interface PaymentInterface {
        void process();
    }

    /**
     * 模拟支付服务
     */
    static class PaymentService implements PaymentInterface {
        @Override
        public void process() {
            System.out.println("处理支付");
        }

        public void refund() {
            System.out.println("处理退款");
        }
    }

    /**
     * 使用建议和注意事项
     */
    public void printBestPractices() {
        System.out.println("\n========== 最佳实践 ==========");
        System.out.println("✓ 1. 仅在调试、日志、工具类中使用");
        System.out.println("✓ 2. 业务代码不应依赖代理类型判断");
        System.out.println("✓ 3. 使用 AopContext.currentProxy() 获取当前代理");
        System.out.println("✓ 4. 启用 @EnableAspectJAutoProxy(exposeProxy = true)");
        System.out.println("✓ 5. 通过接口调用，避免直接依赖实现类");
        System.out.println("==========================================\n");
    }
}

